package com.wujunshen.dumpling.core.process;

import com.wujunshen.dumpling.core.Configuration;
import com.wujunshen.dumpling.database.metadata.IColumn;
import com.wujunshen.dumpling.database.metadata.IDatabase;
import com.wujunshen.dumpling.database.metadata.IPrimaryKey;
import com.wujunshen.dumpling.database.metadata.ITable;
import com.wujunshen.dumpling.database.metadata.model.Column;
import com.wujunshen.dumpling.database.metadata.model.Data;
import com.wujunshen.dumpling.database.metadata.model.Table;
import com.wujunshen.dumpling.database.query.DataBaseQuery;
import com.wujunshen.dumpling.core.query.DataBaseQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.wujunshen.dumpling.common.constant.Constants.*;

/**
 * 数据模型处理
 *
 * @author frankwoo
 */
@Slf4j
public class DataProcess extends AbstractProcess {
  /**
   * 构造方法
   *
   * @param configuration {@link Configuration}
   */
  public DataProcess(Configuration configuration) {
    super(configuration);
  }

  /**
   * 处理
   *
   * @return {@link Data}
   */
  @Override
  public Data process() {
    // 获取query对象
    DataBaseQuery query = new DataBaseQueryFactory(config.getDataSource()).newInstance();

    Data data =
        Data.builder()
            .title(config.getTitle())
            .organization(config.getOrganization())
            .organizationUrl(config.getOrganizationUrl())
            .version(config.getVersion())
            .description(config.getDescription())
            .build();

    /*查询操作开始*/
    long start = System.currentTimeMillis();
    // 获取数据库
    IDatabase dataBase = query.getDataBase();
    log.debug("数据库查询耗时: {}毫秒", (System.currentTimeMillis() - start));
    data.setSchema(dataBase.getDataBase());
    start = System.currentTimeMillis();
    // 获取全部表
    List<? extends ITable> tableList = query.getTables();
    log.debug("数据库表查询耗时: {}毫秒", (System.currentTimeMillis() - start));
    // 获取全部列
    start = System.currentTimeMillis();
    List<? extends IColumn> columnList = query.getAllColumns();
    log.debug("所有数据库表的列查询耗时: {}毫秒", (System.currentTimeMillis() - start));
    // 获取主键
    start = System.currentTimeMillis();
    List<? extends IPrimaryKey> primaryKeyList = query.getPrimaryKeys();
    log.debug("数据库表主键查询耗时: {}毫秒", (System.currentTimeMillis() - start));
    /*查询操作结束*/

    /*处理数据开始*/
    start = System.currentTimeMillis();
    List<Table> tables = new ArrayList<>();
    tablesCaching.put(dataBase.getDataBase(), tableList);
    tableList.forEach(
        table -> {
          handleColumn(columnList, table);
          handlePrimaryKey(primaryKeyList, table);
          wrapperTable(tables, table);
        });

    // 设置表
    data.setTables(filterTables(tables));
    // 优化数据
    optimizeData(data);
    /*处理数据结束*/
    log.debug(
        "处理数据耗时: {}毫秒",
        (System.currentTimeMillis() - start));
    return data;
  }

  private void wrapperTable(List<Table> tableList, ITable iTable) {
    /*封装数据开始*/
    Table table = new Table();
    // 表名称
    table.setTableName(iTable.getTableName());
    // 说明
    table.setRemarks(iTable.getRemarks());
    // 添加表
    tableList.add(table);
    // 处理列
    List<Column> columnModels = new ArrayList<>();
    // 获取主键
    List<String> key =
        primaryKeysCaching.get(iTable.getTableName()).stream()
            .map(IPrimaryKey::getColumnName)
            .collect(Collectors.toList());
    columnsCaching
        .get(iTable.getTableName())
        .forEach(column -> packageColumn(columnModels, key, column));
    // 放入列
    table.setColumns(columnModels);
  }

  /**
   * 处理主键，表名为key，主键为值
   *
   * @param primaryKeyList {@link List}
   * @param iTable {@link ITable}
   */
  private void handlePrimaryKey(List<? extends IPrimaryKey> primaryKeyList, ITable iTable) {
    primaryKeysCaching.put(
        iTable.getTableName(),
        primaryKeyList.stream()
            .filter(primaryKey -> primaryKey.getTableName().equals(iTable.getTableName()))
            .collect(Collectors.toList()));
  }

  /**
   * 处理列，表名为key，列名为值
   *
   * @param columnList {@link List}
   * @param iTable {@link String}
   */
  private void handleColumn(List<? extends IColumn> columnList, ITable iTable) {
    columnsCaching.put(
        iTable.getTableName(),
        columnList.stream()
            .filter(column -> column.getTableName().equals(iTable.getTableName()))
            .collect(Collectors.toList()));
  }

  /**
   * packageColumn
   *
   * @param columnList {@link List}
   * @param keyList {@link List}
   * @param iColumn {@link IColumn}
   */
  private void packageColumn(List<Column> columnList, List<String> keyList, IColumn iColumn) {
    Column column =
        Column.builder()
            // 编号
            .ordinalPosition(iColumn.getOrdinalPosition())
            // 列名
            .columnName(iColumn.getColumnName())
            // 数据类型
            .columnType(iColumn.getColumnType())
            // SQL 数据类型 名称
            .typeName(iColumn.getTypeName())
            // 列长度
            .columnLength(iColumn.getColumnLength())
            // 小数位
            .decimalDigits(
                StringUtils.defaultString(iColumn.getDecimalDigits(), ZERO_DECIMAL_DIGITS))
            // 是否为空
            .isNullable(IS_NULLABLE.equals(iColumn.getIsNullable()) ? N : Y)
            // 是否为主键
            .primaryKey(keyList.contains(iColumn.getColumnName()) ? Y : N)
            // 默认值
            .columnDef(iColumn.getColumnDef())
            // 备注
            .remarks(iColumn.getRemarks())
            .build();
    // 放入集合
    columnList.add(column);
  }
}
